﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using PoolGame2.Controls;

namespace PoolGame2.Game
{
    public abstract class Camera : GameComponent, IGameControlListener
    {
        protected bool activeCamera = false;

        protected bool noClip = false;

        protected float lookAtOffset = 10.0f;
        protected float leftrightRot;
        protected float updownRot;
        
        protected GameObject lookAtTarget = null;
        
        public Matrix projectionMatrix;
        public Matrix viewMatrix;

        protected Vector3 cameraPosition = new Vector3(0, 120, -150);
        protected Vector3 cameraReference;
        protected Vector3 cameraTarget = Vector3.Zero;
        protected Vector3 lookAtRotation = Vector3.Forward;
        protected Vector3 up = Vector3.Up;

        public Camera(PoolGame game)
            : base(game)
        {
        }

        public Vector3 GetPosition()
        {
            return this.cameraPosition;
        }

        public void setActive(bool active)
        {
            activeCamera = active;
        }
        
        public void UpdateProjection(float nearPlane, float farPlane, float fieldOfView)
        {
            float aspectRatio = (float)GameConstants.SCREEN_WIDTH / (float)GameConstants.SCREEN_HEIGHT;
            this.projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(fieldOfView), aspectRatio, nearPlane, farPlane);
        }

        public void UpdateViewMatrix()
        {
            Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot);

            Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
            Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
            Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget;

            Vector3 cameraOriginalUpVector = Vector3.Up;
            Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation);

            viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraRotatedUpVector);
        }
        
        public void LookAtObject(GameObject target, bool lockLook, float lockedOffset)
        {
            lookAtTarget = target;
            lookAtOffset = lockedOffset;
            lookAtRotation = cameraPosition - target.getPosition();
            lookAtRotation.Normalize();
            cameraPosition = lookAtRotation * (-1.0f * lookAtOffset);
        }

        public void DefaultProjection()
        {
            UpdateProjection(0.1f, 1000.0f, 45.0f);
        }

        public abstract void UpdateCamera(GameTime gametime);

        public virtual void GameControlPerformed(List<GameControlAction> actions)
        {
        }

        public Vector2 ConvertToScreenSpace(Vector3 pos)
        {
            Vector3 vec = Game.GraphicsDevice.Viewport.Project( pos, projectionMatrix, viewMatrix, Matrix.Identity );
            return new Vector2(vec.X, vec.Z);
        }
    }
}
